
#ifndef _EKU_FILE_SERVER_H_
#define _EKU_FILE_SERVER_H_

#ifndef RAMFS_TOOLS
#include <inc/types.h>
#endif

struct fs_node_t;

struct fs_stat_t
{
	 uint8_t type;
	 uint32_t size;
};

/* file system interface definition */
/*

  read(f, buf, n)

  if 'f' is a directory, the read function is used to retrive the file
  name of the current pointer.

  Since every file has a filename, if the function returns 0, it means
  that the read routine meets a error.

  If n == 0, the read function will return the length of file name of
  the current pointer.

  Or otherwise, if 'f' is a file, the function trys to read n bytes into the
  buffer, and return the number of bytes that actual read.

*/  
typedef int (*fs_driver_read_t)(struct fs_node_t *f, char *buf, int n);
/*
  write(f, buf, n)
  
  if 'f' is a directory, this function is used to rename a file or to
  search a file in current directory(not include subdirs).

  To find or rename a file, put buf and n so that it represent a filename you
  want to search, then call the write function, the return value 0
  indicates the file has been found successfully and the current
  pointer is moved to the found file, otherwise the searching is failed.

  whether to find or rename a file is decided by the current pointer
  in the file structure. The funciton perform find operation if the
  current pointer does not point to any file. since before you want to
  find or rename a file, be careful about the file pointer.

  Or otherwise, if 'f' is a file, the function will try to write n
  bytes from buffer. And it returns number of bytes that actual
  written.
  
*/
typedef int (*fs_driver_write_t)(struct fs_node_t *f, char *buf, int n);
/*
  seek(f, dir, n)

  if 'f' is a directory, this function is used to reset the current
  file pointer, to the head or to null.

  dir == SEEK_BEGIN -- set to head
  dir == SEEK_FIND  -- set to null

  Or otherwise, 'f' is a file. the function set the read/write pointer
  to a specified position.

  dir == SEEK_BEGIN
  dir == SEEK_FORWARD
  dir == SEEK_BACKWORD
  dir == SEEK_END
  
*/
typedef int (*fs_driver_seek_t)(struct fs_node_t *f, int dir, int n);
/*
  open(d, f)

*/
typedef int (*fs_driver_open_t)(struct fs_node_t *d, struct fs_node_t *f);
typedef int (*fs_driver_stat_t)(struct fs_node_t *d, struct fs_stat_t *attr);
typedef int (*fs_driver_close_t)(struct fs_node_t *f);

typedef int (*fs_driver_roll_t)(struct fs_node_t *d);

typedef int (*fs_driver_create_t)(struct fs_stat_t *attr, char *filename, int n, struct fs_node_t *d);
typedef int (*fs_driver_remove_t)(struct fs_node_t *d);
typedef int (*fs_driver_move_t)(struct fs_node_t *s, struct fs_node_t *d);
typedef int (*fs_driver_copynode_t)(struct fs_node_t *s, struct fs_node_t *d);

struct fs_driver_t
{
	 fs_driver_read_t   read;
	 fs_driver_write_t  write;
	 fs_driver_seek_t   seek;
	 
	 fs_driver_open_t   open;
	 fs_driver_stat_t   stat;
	 fs_driver_close_t  close;
	 
	 fs_driver_roll_t   roll;

	 fs_driver_create_t create;
	 fs_driver_remove_t remove;
	 fs_driver_move_t   move;
	 fs_driver_copynode_t copynode;
};


#define MAX_FS_NODE_COUNT 8192

struct fs_node_t
{
	 // reference count of a file system node
	 uint16_t ref_count;
     // pointer to the driver of this node
	 struct fs_driver_t *dev;
	 // the type of the node, FILE_NORMAL or FILE_DIR
	 uint8_t type;
	 // the synchronization lock
	 struct mutex_t lock;
	 
	 union
	 {
		  void *data;
		  struct fs_node_t *next;
	 };
};

#define FILE_NORMAL 0
#define FILE_DIR    1

// invoked by user init procedure, initialize the file server process, return the err
int init_fs(void);

// unimplemented
struct fs_driver_t *get_driver_by_code(uint8_t code);
// return the root file(directory)
struct fs_node_t *open_root(void);
#ifdef RAMFS_TOOLS
void close_root(void);
#endif
// universal wrapper for drivers {{{
int fs_read(struct fs_node_t *f, void *buf, int n);
int fs_write(struct fs_node_t *f, void *buf, int n);
int fs_seek(struct fs_node_t *f, int dir, int n);

struct fs_node_t *fs_open(struct fs_node_t *d);
int fs_stat(struct fs_node_t *d, struct fs_stat_t *attr);
int fs_close(struct fs_node_t *f);

int fs_roll(struct fs_node_t *d);

int fs_create(struct fs_stat_t *attr, char *filename, int n, struct fs_node_t *d);
int fs_remove(struct fs_node_t *d);
int fs_move(struct fs_node_t *s, struct fs_node_t *d);
struct fs_node_t* fs_copynode(struct fs_node_t *s);

struct fs_node_t *fs_dup(struct fs_node_t *f);
// }}}

#endif /* _EKU_FILE_SERVER_H_ */
